﻿using System.Linq;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Library;
using Microsoft.OData.Edm.Library.Expressions;
using WebApplicationPlayground.Models;

namespace WebApplicationPlayground
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
            modelBuilder.EntitySet<Product>("Products");
            modelBuilder.EntitySet<Customer>("Customers");
            modelBuilder.EntitySet<Order>("Orders");
            modelBuilder.EntityType<SuggestedProduct>();

            modelBuilder.Function("GetSalesTaxRate")
                .Returns<double>()
                .Parameter<int>("PostalCode");

            var model = (EdmModel)modelBuilder.GetEdmModel();

            var entityTypes = model.SchemaElements.OfType<IEdmEntityType>();

            var productEntityType = entityTypes.Single(e => e.Name == "Product");
            var setPrice = new EdmAction("ProductService", "SetPrice",
                returnType: null, isBound: true, entitySetPathExpression: null);
            setPrice.AddParameter("bindingParameter", new EdmEntityTypeReference(productEntityType, isNullable: false));
            IEdmTypeReference intType = EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Int32, isNullable: true);
            setPrice.AddParameter("Price", intType);
            model.AddElement(setPrice);

            IEdmTypeReference decimalType = EdmCoreModel.Instance.GetPrimitive(EdmPrimitiveTypeKind.Decimal, isNullable: true);
            var getPrice = new EdmFunction("ProductService", "GetPrice", decimalType, isBound: true, isComposable: false, entitySetPathExpression: null);
            getPrice.AddParameter("bindingParameter", new EdmEntityTypeReference(productEntityType, isNullable: false));
            model.AddElement(getPrice);


            IEdmTypeReference productTypeRef = new EdmEntityTypeReference(productEntityType, isNullable: false);
            var productMore = new EdmFunction("ProductService", "More", productTypeRef, isBound: true,
                isComposable: false, entitySetPathExpression: new EdmPathExpression("bindingParameter"));
            productMore.AddParameter("bindingParameter", productTypeRef);
            model.AddElement(productMore);

            var productCollectionTypeRef = new EdmCollectionTypeReference(new EdmCollectionType(productTypeRef));
            var productAll = new EdmFunction("ProductService", "All", productCollectionTypeRef, isBound: true,
                isComposable: false, entitySetPathExpression: new EdmPathExpression("bindingParameter"));
            productAll.AddParameter("bindingParameter", productCollectionTypeRef);
            model.AddElement(productAll);

            var orderEntityType = entityTypes.Single(e => e.Name == "Order");
            var orderTypeRef = new EdmEntityTypeReference(orderEntityType, isNullable: false);

            var productInfo1 = new EdmFunction("OrderService", "ProductInfo1", productTypeRef, isBound: true,
                isComposable: false, entitySetPathExpression: new EdmPathExpression("bindingParameter/Product"));
            productInfo1.AddParameter("bindingParameter", orderTypeRef);
            model.AddElement(productInfo1);

            var productInfo2 = new EdmFunction("OrderService", "ProductInfo2", orderTypeRef, isBound: true,
                isComposable: false, entitySetPathExpression: new EdmPathExpression("bindingParameter"));
            productInfo2.AddParameter("bindingParameter", orderTypeRef);
            model.AddElement(productInfo2);

            var customerEntityType = entityTypes.Single(e => e.Name == "Customer");
            var customerTypeRef = new EdmEntityTypeReference(customerEntityType, isNullable: false);
            var customerCollectionTypeRef = new EdmCollectionTypeReference(new EdmCollectionType(customerTypeRef));
            var orderCollectionTypeRef = new EdmCollectionTypeReference(new EdmCollectionType(orderTypeRef));
            var ordersList = new EdmFunction("CustomerService", "OrdersList", orderCollectionTypeRef, isBound: true,
                isComposable: false, entitySetPathExpression: new EdmPathExpression("bindingParameter/Orders"));
            ordersList.AddParameter("bindingParameter", customerCollectionTypeRef);
            model.AddElement(ordersList);

            var suggestedProductEntityType = entityTypes.Single(e => e.Name == "SuggestedProduct");
            var suggestedProductTypeRef = new EdmEntityTypeReference(suggestedProductEntityType, isNullable: false);
            var suggestedProduct = new EdmFunction("OrderService", "SuggestedProduct", suggestedProductTypeRef, isBound: true,
                isComposable: false, entitySetPathExpression: new EdmPathExpression("bindingParameter/SuggestedProduct"));
            suggestedProduct.AddParameter("bindingParameter", orderTypeRef);
            model.AddElement(suggestedProduct);

            config.MapODataServiceRoute(
                routeName: "ODataRoute",
                routePrefix: null,
                model: model);

            config.EnsureInitialized();
        }
    }
}
